// Copyright (C) 2005 Taylor L. Riché <riche@cs.utexas.edu>
//  
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software 
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// 	$Id: FuncFeatures.java 263 2005-10-03 17:25:02Z richetl $	
//

import java.util.*;
import java.io.*;

class FuncFeatures
{
    class FeatureNode 
    {
	private boolean enabled;
	private String parameter;

	static public final String NONE = "none";

	public FeatureNode() {
	    parameter = NONE;
	}

	public void setEnabled(boolean e) {
	    enabled = true;
	}
	public boolean isEnabled() {
	    return enabled;
	}
	public void setParameter(String p) {
	    parameter = p;
	}
	public String getParameter() {
	    return parameter;
	}
    }

    class BadFeatureParameterException extends Exception {
	private String badParameter;
	public BadFeatureParameterException(String param) {
	    badParameter = param;
	}
	public String getBadParameter() {
	    return badParameter;
	}
    }
    
    private HashMap featureMap;
    private boolean flow;
    private boolean stateful;
    private int flowSig;

    static private final String FIVET = "FIVET";
    static private final String SRCDEST_IP = "SRCDEST_IP";
    static private final String SRC_IP_PORT = "SRC_IP_PORT";
    static private final String FLOW = "flow";
    static private final String FLOWCLASS = "FlowFunction";
    static private final String STATEFUL = "stateful";
    static private final String STATEFULCLASS = "StatefulFunction";
    
    public FuncFeatures() {
	featureMap = new HashMap();
    }

    public void setFeature(String feature, String parameter) {
	FeatureNode fn = new FeatureNode();
	fn.setEnabled(true);
	fn.setParameter(parameter);
	featureMap.put(feature, fn);
    }

    public void setFeature(String feature) {
	FeatureNode fn = new FeatureNode();
	fn.setEnabled(true);
	featureMap.put(feature, fn);
    }

    public void print(PrintStream file) {
	Iterator keyValuePairs = featureMap.entrySet().iterator();
	file.print(" : ");
	int mapSize = featureMap.size();
	for (int i = 0; i < mapSize; i++) {
	    Map.Entry entry = (Map.Entry) keyValuePairs.next();
	    String key = (String)entry.getKey();
	    file.print("public ");
	    if(key.equals(FLOW)) {
		file.print("lee::" + FLOWCLASS);
	    }
	    else if(key.equals(STATEFUL)) {
		file.print("lee::" + STATEFULCLASS);
	    }
	    file.print(", ");
	}
    }

    public void printIncludes(PrintStream file) {
	Iterator keyValuePairs = featureMap.entrySet().iterator();
	int mapSize = featureMap.size();
	for (int i = 0; i < mapSize; i++) {
	    Map.Entry entry = (Map.Entry) keyValuePairs.next();
	    String key = (String)entry.getKey();
	    file.print("#include <lee/");
	    if(key.equals(FLOW)) {
		file.print(FLOWCLASS);
	    }
	    else if(key.equals(STATEFUL)) {
		file.print(STATEFULCLASS);
	    }
	    file.println(".hh>");
	}
    }

    public void printPubs(PrintStream file) {
	FeatureNode fn = null;
	if((fn = (FeatureNode)featureMap.get(FLOW)) != null) {
	    file.println("\tvirtual void * getState(const lee::FlowList & l);");
	    file.println("\tvirtual void installState(const lee::FlowMap & state);");
	}
	if(featureMap.get(STATEFUL) != null) {
	    file.println("\tvirtual void * getState();");
	    file.println("\tvirtual void installState(void * state);");
	}
    }

    public void printPrivs(PrintStream file) {
	FeatureNode fn = null;
	if((fn = (FeatureNode)featureMap.get(FLOW)) != null) {
	    if(fn.getParameter() == FeatureNode.NONE) {
		file.println("\tvirtual FlowId * getFlowID(lee::PktData * p);");
	    }
	}
    }
    
    public void printSwitches(PrintStream file) throws BadFeatureParameterException {
	FeatureNode fn = null;
	if((fn = (FeatureNode)featureMap.get(FLOW)) != null) {
	    if(fn.getParameter().equals(FIVET) ||
	       fn.getParameter().equals(SRCDEST_IP) ||
	       fn.getParameter().equals(SRC_IP_PORT)) {
		file.println("\t\tsetFlowSig(lee::" + fn.getParameter() + ");");
	    }
	    else if(fn.getParameter().equals(FeatureNode.NONE)) {
		return;
	    }
	    else {
		throw new BadFeatureParameterException(fn.getParameter());
	    }
	}
    }  

}
